package org.jeecg.modules.mq;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.MQConstant;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.constant.ConsumerConstant;
import org.jeecg.constant.ElasticSearchConstant;
import org.jeecg.constant.RedisConstant;
import org.jeecg.modules.article.entity.Article;
import org.jeecg.modules.article.service.IArticleService;
import org.jeecg.modules.columnTopic.entity.ColumnTopicPublish;
import org.jeecg.modules.columnTopic.service.IColumnTopicPublishService;
import org.jeecg.modules.columnmanager.service.IColumnManagerService;
import org.jeecg.modules.es.service.ElasticSearchService;
import org.jeecg.modules.es.vo.KnowledgeVO;
import org.jeecg.modules.knowledge.entity.PhilKnowledge;
import org.jeecg.modules.knowledgeType.service.IKnowledgeColumnService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * TODO: ActiveMQ的消费者
 *
 * @author Zhang Hao yu
 * @date 2020/12/4 19:21
 */
@Component
@Slf4j
public class ActiveMqConsumer {
    @Autowired
    private IArticleService articleService;

    @Autowired
    private IColumnTopicPublishService columnTopicPublishService;

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IColumnManagerService columnManagerService;
    @Autowired
    private ElasticSearchService elasticSearchService;
    @Autowired
    private IKnowledgeColumnService knowledgeColumnService;
    /**
     * TODO: es更新文章
     *
     *
     * @author ZhangHaoyu
     * @param article 修改的文章
     * @return void
     */
    @JmsListener(destination = MQConstant.PHIL_ES_UPDATE)
    public void esUpdate (Article article) {
        System.out.println(article);
    }


    /**
     * TODO: 更新Redis
     *
     *
     * @author ZhangHaoyu
     * @param msg ConsumerConstant
     * @return void
     */
    @JmsListener(destination = MQConstant.PHIL_UPDATE_REDIS)
    public void redisUpdate (String msg) throws InterruptedException {
        // 更新轮播图
        if (ConsumerConstant.ROTATION.equals(msg)){
            log.info("=============================更新轮播图=================================");
            Thread.sleep(TimeUnit.SECONDS.toMillis(2));
            articleService.getTopRotation(1);
        }
    }

    /**
     * TODO: 订阅功能的串行操作，防止并发
     *  1. 信息异步入库Redis
     *  2. 信息异步出库Redis
     *  3. 删除某栏目下某用户的推送文章
     *
     *
     * @author ZhangHaoyu
     * @param map 数据包     格式  K：V
     *              operation  操作
     *              info  携带的数据
     * @return void
     */
    @JmsListener(destination = MQConstant.PHIL_OPERATE_TOPIC_REDIS)
    public void updateTopicArticleRedis (HashMap<String, Object> map) {
        String operation = (String) map.get(MQConstant.OPERATION);
        String info = (String) map.get(MQConstant.INFO);
        switch (operation){
            case ConsumerConstant.PHIL_INSERT_TOPIC_TO_REDIS:
                insertTopicTORedis(info);
                break;
            case ConsumerConstant.PHIL_DELETE_TOPIC_FROM_REDIS:
                deleteTopicFromRedis(info);
                break;
            case ConsumerConstant.PHIL_CLEAR_COLUMN_PUBLISH_ARTICLE:
                clearUserPublishArticle(info);
                break;
            case ConsumerConstant.PHIL_PUBLISH_ARTICLE:
                Article article = JSON.parseObject(info, Article.class);
                publish(article);
                insertDocument(article);
                break;
            case ConsumerConstant.PHIL_PUBLISH_KNOWLEDGE:
                PhilKnowledge knowledge = JSON.parseObject(info,PhilKnowledge.class);
                publishKnowledge(knowledge);
                break;
            default:
                break;
        }
    }

    /**
     * TODO: 向订阅了知识库的用户进行推送
     *       更新es
     *
     *
     * @author ZhangHaoyu
     * @param knowledge 知识
     * @return void
     */
    private void publishKnowledge(PhilKnowledge knowledge) {
        // 异步更新es
        insertKnowledge(knowledge);
        // 新增文章消息推送
        String id = knowledge.getId();
        String knowledgeColumn = knowledge.getKnowledgeType();
        // 获取父类的id
        String dictId = knowledgeColumnService.getIdByName(knowledgeColumn);
        // 新增文章消息推送
        String redisKey = RedisConstant.ARTICLE_PUBLISH + dictId;

        // 连接redis获取节点
        Object obj = redisUtil.get(redisKey);
        if (Objects.isNull(obj)){
            // 如果根节点是空，那么创建节点
            HashMap<String,Object> map = new HashMap<>();
            redisUtil.set(redisKey,map);
            return;
        }
        List<ColumnTopicPublish> list = columnTopicPublishService.list(
                new LambdaQueryWrapper<ColumnTopicPublish>()
                        .eq(ColumnTopicPublish::getColumnId,dictId));
        if (list.isEmpty()){
            // 如果集合为空，直接结束此方法
            return;
        }
        HashMap<String, Object> map = (HashMap<String, Object>) obj;
        for (int i = 0; i < list.size(); i++) {
            String openId = list.get(i).getOpenId();
            HashSet<String> set = (HashSet<String>) map.get(openId);
            set.add(id);
            map.put(openId,set);
        }

        redisUtil.set(redisKey,map);

    }
    /**
     * TODO: 清空用户在该栏目中的新推文章，
     *  此方法用在用户点击我的订阅中的栏目后
     *
     *
     * @author ZhangHaoyu
     * @param msg
     * @return void
     */
    private void clearUserPublishArticle(String msg) {
        JSONObject info = JSONObject.parseObject(msg);
        String columnId = info.getString("columnId");
        String openId = info.getString("openId");
        Object o = redisUtil.get(RedisConstant.ARTICLE_PUBLISH + columnId);
        HashMap<String, Object> map = (HashMap<String, Object>) o;
        map.put(openId,new HashSet<String>());
        redisUtil.set(RedisConstant.ARTICLE_PUBLISH+columnId,map);
    }

    /**
     * TODO: 信息异步出库Redis
     *
     *
     * @author ZhangHaoyu
     * @param msg
     * @return void
     */
    private void deleteTopicFromRedis(String msg) {
        JSONObject info = JSONObject.parseObject(msg);
        // 更新redis，删除对应节点
        String columnId = info.getString("columnId");
        String openId = info.getString("openId");
        Object o = redisUtil.get(RedisConstant.ARTICLE_PUBLISH + columnId);
        HashMap<String, Object> map = (HashMap<String, Object>) o;
        map.remove(openId);
        redisUtil.set(RedisConstant.ARTICLE_PUBLISH + columnId,map);
    }

    /**
     * TODO:信息异步入库Redis
     *
     *
     * @author ZhangHaoyu
     * @param info
     * @return void
     */
    private void insertTopicTORedis(String info) {
        JSONObject msg = JSONObject.parseObject(info);
        String columnId = msg.getString("columnId");
        // 更新redis中对应栏目，添加一个新节点
        HashSet<String> set = new HashSet<>();
        Object o = redisUtil.get(RedisConstant.ARTICLE_PUBLISH + columnId);
        HashMap<String,Object> map = (HashMap<String, Object>) o;
        map.put(msg.getString("openId"),set);
        redisUtil.set(RedisConstant.ARTICLE_PUBLISH+columnId,map);
    }

    /**
     * TODO: 获取文章详情，异步推送  已废弃！！
     *
     *
     * @author ZhangHaoyu
     * @param msg
     * @return void
     */
   /* @JmsListener(destination = MQConstant.PHIL_COLUMN_PUBLISH,containerFactory = "jmsListenerContainerTopic")
    public void publish (Article msg){
        //获取Access_token
        String accessToken = wxService.getAccessToken();
        // 封装信息
        String articleAuthor = msg.getArticleAuthor();
        Date createTime = msg.getCreateTime();
        String articleTitle = msg.getArticleTitle();
        String articleColumn = msg.getArticleColumn();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String articleCreateTimeStr = sdf.format(createTime);
        // 封装信息
        WxMessageVO wxMessageVO = new WxMessageVO();
        wxMessageVO.setTouser("用户openId");
        wxMessageVO.setTemplate_id(WXConstant.WX_TOPIC_TEMP_ID);
        Map<String, TemplateData> map = new HashMap<>();
        map.put("thing1",new TemplateData(articleTitle));
        map.put("thing2",new TemplateData(articleAuthor));
        map.put("time3",new TemplateData(articleCreateTimeStr));
        map.put("thing4",new TemplateData(articleColumn));
        wxMessageVO.setData(map);

        // 调用接口发送推送
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="+accessToken;


        String resp = restTemplate.postForObject(url, wxMessageVO, String.class);
        System.out.println(resp);
    }*/


    /**
     * TODO: 获取文章详情，异步推送
     *
     *
     * @author ZhangHaoyu
     * @param article
     * @return void
     */
//     @JmsListener(destination = MQConstant.PHIL_COLUMN_PUBLISH,containerFactory = "jmsListenerContainerTopic")
    public void publish (Article article){
         String articleId = article.getId();
         String articleColumn = article.getArticleColumn();
         // 根据栏目名称获取栏目id
         String columnId = columnManagerService.getIdByName(articleColumn);

         String redisKey = RedisConstant.ARTICLE_PUBLISH+columnId;
         // 获取当前栏目下的用户集合
         List<ColumnTopicPublish> list = columnTopicPublishService.list(
                 new LambdaQueryWrapper<ColumnTopicPublish>()
                         .eq(ColumnTopicPublish::getColumnId, columnId));
         // 加锁
         // 获取当前栏目redis中的信息
         Object obj = redisUtil.get(redisKey);
         // map:${用户openId}:${文章Set}
             HashMap<String, Object> map = (HashMap<String, Object>) obj;
         // 根据用户信息，来更新map中的信息，文章set或者用户key
         for (int i = 0; i < list.size(); i++) {
             String openId = list.get(i).getOpenId();
             HashSet<String> set = (HashSet<String>) map.get(openId);
             set.add(articleId);
             map.put(openId,set);
         }
             redisUtil.set(redisKey,map);
     }

     /**
      * TODO: 异步更新es，插入文章
      *
      *
      * @author ZhangHaoyu
      * @param article
      * @return void
      */
    public void insertDocument(Article article){
        try {
            article.setArticleImageString(article.getArticleImageString());
            article.setArticleImage(article.getArticleImage());
            elasticSearchService.insertSource(article, ElasticSearchConstant.PHIL_ARTICLE);
        } catch (IOException e) {
            log.debug("文章插入失败=====id=="+article.getId());
            e.printStackTrace();
        }
    }
    /**
     * TODO: 异步更新es，插入知识
     *
     *
     * @author ZhangHaoyu
     * @param knowledge
     * @return void
     */
    public void insertKnowledge(PhilKnowledge knowledge){
        try {
            knowledge.setKnowledgeImageString(knowledge.getKnowledgeImageString());
            KnowledgeVO knowledgeVO = new KnowledgeVO();
            BeanUtils.copyProperties(knowledge,knowledgeVO);
            String[] split = knowledge.getKnowledgeKeywords().split(",");
            List<String> strings = Arrays.asList(split);
            knowledgeVO.setKeywordList(strings);
            elasticSearchService.insertSource(knowledgeVO, ElasticSearchConstant.PHIL_KNOWLEDGE);
        } catch (IOException e) {
            log.debug("知识插入失败=====id=="+knowledge.getId());
            e.printStackTrace();
        }
    }
}